home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / DRSI.C < prev    next >
Text File  |  1993-08-09  |  30KB  |  1,043 lines

  1. /*
  2.  * Version with Stopwatches
  3.  *
  4.  * 0 - Not used
  5.  * 1 - rx_fsm run time
  6.  * 2 - drtx_active run time (per character tx time)
  7.  * 
  8.  * Interface driver for the DRSI board for KA9Q's TCP/IP on an IBM-PC ONLY!
  9.  *
  10.  * Derived from a driver written by Art Goldman, WA3CVG
  11.  * (c) Copyright 1987 All Rights Reserved
  12.  * Permission for non-commercial use is hereby granted provided this notice
  13.  * is retained.  For info call: (301) 997-3838.
  14.  *
  15.  * Heavily re-written from the original,  a driver for the EAGLE board into
  16.  * a driver for the DRSI PC* Packet adpator. Copyright as original, all
  17.  * amendments likewise providing credit given and notice retained.
  18.  * Stu Phillips - N6TTO, W6/G8HQA (yes Virginia,  really !).
  19.  * For info call: (408) 285-4142
  20.  *
  21.  * This driver supports 1 (one) DRSI board.
  22.  * 
  23.  * Reformatted and added ANSI-style declarations, integrated into NOS
  24.  * by KA9Q, 10/14/89
  25.  *
  26.  * Latest set of defect fixes added 1/2/90 by N6TTO
  27.  * 1. Made P-PERSIST work properly
  28.  * 2. Fixed UNDERRUN bug when in DEFER state
  29.  * 3. Tx now defers correctly when DCD is high (!)
  30.  *
  31.  * Changed 3/4/90 by N6TTO
  32.  * Changed method of enabling the IRQ to the 8259 to call maskon()
  33.  * instead of clrbit(); change made to allow interrupts > 8 to work
  34.  * on an AT.
  35.  *
  36.  * Changed 11/14/90 by N6TTO
  37.  * Fixed incompatiblity between current NOS memory allocation scheme
  38.  * and changes made to speed up drsi transmit state machine.
  39.  *
  40.  */
  41.  
  42. #include <stdio.h>
  43. #include <dos.h>
  44. #include <time.h>
  45. #include "global.h"
  46. #include "config.h"
  47. #ifdef DRSI
  48. #include "mbuf.h"
  49. #include "iface.h"
  50. #include "pktdrvr.h"
  51. #include "netuser.h"
  52. #include "drsi.h"
  53. #include "ax25.h"
  54. #include "trace.h"
  55. #include "pc.h"
  56. #include "n8530.h"
  57. #include "devparam.h"
  58.  
  59. static int32 dr_ctl __ARGS((struct iface *iface,int cmd,int set,int32 val));
  60. static int dr_raw __ARGS((struct iface *iface,struct mbuf *bp));
  61. static int dr_stop __ARGS((struct iface *iface,int tmp));
  62. static void dr_wake __ARGS((struct drchan *hp,int rx_or_tx,
  63.     void (*routine) __ARGS((struct drchan *)),int ticks));
  64. static int drchanparam __ARGS((struct drchan *hp));
  65. static void drexint __ARGS((struct drchan *hp));
  66. static void drinitctc __ARGS((unsigned port));
  67. static void drrx_active __ARGS((struct drchan *hp));
  68. static void drrx_enable __ARGS((struct drchan *hp));
  69. static void drtx_active __ARGS((struct drchan *hp));
  70. static void drtx_defer __ARGS((struct drchan *hp));
  71. static void drtx_downtx __ARGS((struct drchan *hp));
  72. static void drtx_flagout __ARGS((struct drchan *hp));
  73. static void drtx_idle __ARGS((struct drchan *hp));
  74. static void drtx_rrts __ARGS((struct drchan *hp));
  75. static void drtx_tfirst __ARGS((struct drchan *hp));
  76. static char read_ctc __ARGS((unsigned port,unsigned reg));
  77. static void rx_fsm __ARGS((struct drchan *hp));
  78. static void tx_fsm __ARGS((struct drchan *hp));
  79. static void write_ctc __ARGS((unsigned port,unsigned reg,unsigned val));
  80.  
  81. static struct DRTAB Drsi[DRMAX];   /* Device table - one entry per card */
  82. INTERRUPT (*Drhandle[]) __ARGS((void)) = { dr0vec };  /* handler interrupt vector table */
  83. static struct drchan Drchan[2*DRMAX] = {0,0};   /* channel table - 2 entries per card */
  84. static int16 Drnbr = 0;
  85.  
  86. /* Set specified routine to be 'woken' up after specified number
  87.  * of ticks (allows CPU to be freed up and reminders posted);
  88.  */
  89. static void
  90. dr_wake(hp, rx_or_tx, routine, ticks)
  91. struct drchan *hp;
  92. int rx_or_tx;
  93. void (*routine) __ARGS((struct drchan *));
  94. int ticks;
  95. {
  96.     hp->w[rx_or_tx].wcall = routine;
  97.     hp->w[rx_or_tx].wakecnt = ticks;
  98. }
  99.  
  100. /* Master interrupt handler.  One interrupt at a time is handled.
  101.  * here. Service routines are called from here.
  102.  */
  103. void
  104. drint(int dev)
  105. {
  106.     char st;
  107.     int16 i;
  108.     int16 pcbase = Drsi[dev].addr;
  109.     struct drchan *hpa = &Drchan[2 * dev];
  110.     struct drchan *hpb = &Drchan[(2 * dev)+1];
  111.  
  112.     Drsi[dev].ints++;
  113.  
  114. yuk:
  115.     /* Check CTC for timer interrupt */
  116.     st = read_ctc(pcbase, Z8536_CSR3);
  117.     if(st & Z_IP){
  118.         /* Reset interrupt pending */
  119.         write_ctc(pcbase, Z8536_CSR3, Z_CIP|Z_GCB);
  120.         for(i = 0; i <= 1; i++) {
  121.             if(hpa->w[i].wakecnt) {
  122.                 if(--hpa->w[i].wakecnt == 0) {
  123.                     (hpa->w[i].wcall)(hpa);
  124.                 }
  125.             }
  126.             if(hpb->w[i].wakecnt){
  127.                 if(--hpb->w[i].wakecnt == 0) {
  128.                     (hpb->w[i].wcall)(hpb);
  129.                 }
  130.             }
  131.         }
  132.     }
  133.     /* Check the SIO for interrupts */
  134.  
  135.     /* Read interrupt status register from channel A */
  136.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0){
  137.         /* Use IFs to process ALL interrupts pending
  138.          * because we need to check all interrupt conditions
  139.          */
  140.         if(st & CHARxIP){
  141.             /* Channel A Rcv Interrupt Pending */
  142.             rx_fsm(hpa);
  143.         }
  144.         if(st & CHBRxIP){
  145.             /* Channel B Rcv Interrupt Pending */
  146.             rx_fsm(hpb);
  147.         }
  148.         if(st & CHATxIP){
  149.             /* Channel A Transmit Int Pending */
  150.             tx_fsm(hpa);
  151.         }
  152.         if(st & CHBTxIP){
  153.             /* Channel B Transmit Int Pending */
  154.             tx_fsm(hpb);
  155.         }
  156.         if(st & CHAEXT){
  157.             /* Channel A External Status Int */
  158.             drexint(hpa);
  159.         }
  160.         if(st & CHBEXT){
  161.             /* Channel B External Status Int */
  162.             drexint(hpb);
  163.         }
  164.         /* Reset highest interrupt under service */
  165.         write_scc(hpa->base+CTL,R0,RES_H_IUS);
  166.  
  167.     } /* End of while loop on int processing */
  168.     if(read_ctc(pcbase, Z8536_CSR3) & Z_IP)
  169.         goto yuk;
  170. }
  171.  
  172.  
  173. /* DRSI SIO External/Status interrupts
  174.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  175.  * Receiver automatically goes to Hunt on an abort.
  176.  *
  177.  * If the Tx Underrun interrupt hits, change state and
  178.  * issue a reset command for it, and return.
  179.  */
  180. static void
  181. drexint(struct drchan *hp)
  182. {
  183.     int base = hp->base;
  184.     char st;
  185.  
  186.     hp->exints++;
  187.  
  188.     DISABLE();
  189.     st = read_scc(base+CTL,R0);         /* Fetch status */
  190.  
  191.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  192.         /* Note that the TxEOM bit remains set once we go    */
  193.     /* back to receive.  The following qualifications    */
  194.     /* are necessary to prevent an aborted frame causing */
  195.     /* a queued transmit frame to be tossed when in      */
  196.     /* DEFER state on transmit.                 */
  197.     if((hp->tstate != DEFER) && (hp->rstate==0) && (st & TxEOM)){
  198.         if(hp->tstate != UNDERRUN){
  199.             /* This is an unexpected underrun.  Discard the current
  200.              * frame (there's no way to rewind),  kill the transmitter
  201.              * and return to receive with a wakeup posted to get the
  202.              * next (if any) frame.  Any recovery will have to be done
  203.              * by higher level protocols (yuk).
  204.              */
  205.             write_scc(base, R5, Tx8|DTR);    /* Tx off now */
  206.             write_scc(base, R1, 0);        /* Prevent ext.status int */
  207.             write_scc(base, R0, RES_Tx_P);  /* Reset Tx int pending */
  208.             write_scc(base, R0, ERR_RES);
  209.             write_scc(base, R0, RES_EOM_L); /* Reset underrun latch */
  210.             free_p(hp->sndbuf);
  211.             hp->tstate = IDLE;
  212.             hp->tx_state = drtx_idle;
  213.             dr_wake(hp, TX, tx_fsm, hp->slotime);
  214.             hp->rstate = ENABLE;
  215.             hp->rx_state = drrx_enable;
  216.             drrx_enable(hp);
  217.         }
  218.     }
  219.     /* Receive Mode only
  220.      * This triggers when hunt mode is entered, & since an ABORT
  221.      * automatically enters hunt mode, we use that to clean up
  222.      * any waiting garbage
  223.      */
  224.     if((hp->rstate != IDLE) && (st & BRK_ABRT)){
  225.         if(hp->rcvbuf != NULLBUF){
  226.             hp->rcp = hp->rcvbuf->data;
  227.             hp->rcvbuf->cnt = 0;
  228.         }
  229.         while(read_scc(base,R0) & Rx_CH_AV)
  230.             (void) inportb(base+DATA);
  231.         hp->aborts++;
  232.         hp->rstate = ACTIVE;
  233.         write_scc(base, R0, ERR_RES);
  234.     }
  235.     /* reset external status latch */
  236.     write_scc(base,R0,RES_EXT_INT);
  237.     RESTORE();
  238. }
  239.  
  240. /* Receive Finite State Machine - dispatcher */
  241. static void
  242. rx_fsm(struct drchan *hp)
  243. {
  244.     DISABLE();
  245.     hp->rxints++;
  246.     (*hp->rx_state)(hp);
  247.     RESTORE();
  248. }
  249.  
  250. /* drrx_enable
  251.  * Receive ENABLE state processor
  252.  */
  253. static void
  254. drrx_enable(struct drchan *hp)
  255. {
  256.     int16 base = hp->base;
  257.  
  258.     write_scc(base, R1, INT_ALL_Rx|EXT_INT_ENAB);
  259.     write_scc(base, R15, BRKIE);    /* Allow ABORT Int */
  260.     write_scc(base, R14, BRSRC|BRENABL|SEARCH);
  261.     /* Turn on rx and enter hunt mode */
  262.     write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  263.  
  264.     if(hp->rcvbuf != NULLBUF){
  265.         hp->rcvbuf->cnt = 0;
  266.         hp->rcp = hp->rcvbuf->data;
  267.     }
  268.     hp->rstate = ACTIVE;
  269.     hp->rx_state = drrx_active;
  270. }
  271.  
  272. /* drrx_active
  273.  * Receive ACTIVE state processor
  274.  */
  275. static void
  276. drrx_active(struct drchan *hp)
  277. {
  278.     int16 base = hp->base;
  279.     unsigned char rse,st;
  280.  
  281.     /* Allocate a receive buffer if not already present */
  282.     if(hp->rcvbuf == NULLBUF){
  283.         if((hp->rcvbuf = alloc_mbuf(hp->bufsiz)) == NULLBUF) {
  284.             /* No buffer - abort the receiver */
  285.             write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  286.             /* Clear character from rx buffer in SIO */
  287.             inportb(base+DATA);
  288.             return;
  289.         }
  290.         hp->rcvbuf->cnt = 0;
  291.         hp->rcp = hp->rcvbuf->data;
  292.     }
  293.  
  294.     st = read_scc(base, R0); /* get interrupt status from R0 */
  295.     rse = read_scc(base,R1); /* get special status from R1 */
  296.  
  297.     if(st & Rx_CH_AV){
  298.         /* there is a char to be stored
  299.          * read special condition bits before reading the data char
  300.          * (already read above)
  301.          */
  302.         if(rse & Rx_OVR){
  303.             /* Rx overrun - toss buffer */
  304.             hp->rcp = hp->rcvbuf->data;            /* reset buffer pointers */
  305.             hp->rcvbuf->cnt = 0;
  306.             hp->rstate = RXERROR;                /* set error flag */
  307.             hp->rovers++;                        /* count overruns */
  308.         } else if(hp->rcvbuf->cnt >= hp->bufsiz){
  309.             /* Too large -- toss buffer */
  310.             hp->toobig++;
  311.             hp->rcp = hp->rcvbuf->data;            /* reset buffer pointers */
  312.             hp->rcvbuf->cnt = 0;
  313.             hp->rstate = TOOBIG;                /* when set, chars are not stored */
  314.         }
  315.         /* ok, we can store the received character now */
  316.         if((hp->rstate == ACTIVE) && ((st & BRK_ABRT) == 0)){
  317.             *hp->rcp++ = inportb(base+DATA); /* char to rcv buff */
  318.             hp->rcvbuf->cnt++;                     /* bump count */
  319.         } else {
  320.             /* got to empty FIFO */
  321.             inportb(base+DATA);
  322.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  323.             hp->rcvbuf->cnt = 0;
  324.             hp->rstate = RXABORT;
  325.             write_scc(base,R0,ERR_RES);    /* reset err latch */
  326.         }
  327.     }
  328.     /* The End of Frame bit is ALWAYS associated with a character,
  329.      * usually, it is the last CRC char.  Only when EOF is true can
  330.      * we look at the CRC byte to see if we have a valid frame
  331.      */
  332.     if(rse & END_FR){
  333.         hp->rxframes++;
  334.         /* END OF FRAME -- Make sure Rx was active */
  335.         if(hp->rcvbuf->cnt > 0){    /* any data to store */
  336.             /* looks like a frame was received
  337.              * now is the only time we can check for CRC error
  338.              */
  339.             if((rse & CRC_ERR)
  340.               || (hp->rstate > ACTIVE)
  341.               || (hp->rcvbuf->cnt < 10)
  342.               || (st & BRK_ABRT)) {
  343.                 /* error occurred; toss frame */
  344.                 if(rse & CRC_ERR)
  345.                     hp->crcerr++;                /* count CRC errs */
  346.                 hp->rcp = hp->rcvbuf->data;
  347.                 hp->rcvbuf->cnt = 0;
  348.                 hp->rstate = ACTIVE;               /* Clear error state */
  349.             } else {
  350.                 /* Here we have a valid frame */
  351.                 struct mbuf *bp = alloc_mbuf(sizeof(struct phdr));
  352.                 struct phdr *phdr = (struct phdr *)bp->data;
  353.                 bp->cnt = sizeof(struct phdr);
  354.                 phdr->type = CL_AX25;
  355.                 phdr->iface = hp->iface;
  356.                 bp->next = hp->rcvbuf;
  357.                 hp->rcvbuf->cnt -= 2;            /* chuck FCS bytes */
  358.                 enqueue(&Hopper,bp);            /* queue it in */
  359.                 hp->enqueued++;
  360.                 /* packet queued - reset buffer pointer */
  361.                 hp->rcvbuf = NULLBUF;
  362.             } /* end good frame queued */
  363.         }  /* end check for active receive upon EOF */
  364.     }
  365. }
  366.  
  367. /*
  368.  * TX finite state machine - dispatcher
  369.  */
  370. static void
  371. tx_fsm(struct drchan *hp)
  372. {
  373.     DISABLE();
  374.     if(hp->tstate != DEFER && hp->tstate)
  375.         hp->txints++;
  376.     (*hp->tx_state)(hp);
  377.     RESTORE();
  378. }
  379.  
  380. /* drtx_idle
  381.  * Transmit IDLE transmit state processor
  382.  */
  383. static void
  384. drtx_idle(struct drchan *hp)
  385. {
  386.     int16 base;
  387.  
  388.     /* Tx idle - is there a frame to transmit ? */
  389.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  390.         /* Nothing to send - return to receive mode
  391.          * Turn Tx off - any trailing flag should have been sent
  392.          * by now
  393.          */
  394. #ifdef DRSIDEBUG
  395.         tputs("Nothing to TX\n");
  396. #endif
  397.         base = hp->base;
  398.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  399.         write_scc(base, R0, ERR_RES);    /* Reset error bits */
  400.  
  401.         /* Delay for squelch tail before enabling receiver */
  402.         hp->rstate = ENABLE;
  403.         hp->rx_state = drrx_enable;
  404.         dr_wake(hp, RX, rx_fsm, hp->squeldelay);
  405.     } else {
  406.         /* Frame to transmit */
  407.         hp->tstate = DEFER;
  408.         hp->tx_state = drtx_defer;
  409.         drtx_defer(hp);
  410.     }
  411. }
  412.  
  413. /* drtx_defer
  414.  * Transmit DEFER state processor
  415.  */
  416. static void
  417. drtx_defer(struct drchan *hp)
  418. {
  419.     int16 base = hp->base;
  420.  
  421.     /* We may have defered a previous tx attempt - in any event...
  422.      * Check DCD in case someone is already transmitting
  423.      * then check to see if we should defer due to P-PERSIST.
  424.      */
  425.  
  426. #ifdef DRSIDEBUG
  427.     tputs("drtx_defer - checking for DCD\n");
  428. #endif
  429.     if((read_scc(base+CTL, R0) & DCD) > 0){
  430.         /* Carrier detected - defer */
  431.         hp->txdefers++;
  432.         dr_wake(hp, TX, tx_fsm, 10);    /* Defer for 100 mS */
  433. #ifdef DRSIDEBUG
  434.         tputs("drtx_defer - TX deferred\n");
  435. #endif
  436.         return;
  437.     }
  438.  
  439. #ifdef DRSIDEBUG
  440.     tputs("drtx_defer - checking for P-PERSIST backoff\n");
  441. #endif
  442.     /* P-PERSIST is checked against channel 3 of the 8536 which is
  443.      * the free running counter for the 10 mS tick; The counter
  444.      * goes through 0x6000 ticks per 10 mS or one tick every
  445.      * 407 nS - this is pretty random compared to the DOS time of
  446.      * day clock (0x40:0x6C) used by the other (EAGLE) drivers.
  447.      */
  448.         if (hp->persist <= read_ctc(base,Z8536_CC3LSB)) {
  449. #ifdef DRSIDEBUG
  450.         tputs("drtx_defer - BACKOFF\n");
  451. #endif
  452.         hp->txppersist++;
  453.         dr_wake (hp, TX, tx_fsm, hp->slotime);
  454.         return;
  455.     }
  456.     /* No backoff - set RTS and start to transmit frame */
  457.     write_scc(base, R1, 0);        /* Prevent external status int */
  458.     write_scc(base, R3, Rx8);    /* Turn Rx off */
  459.     hp->rstate = IDLE;        /* Mark Rx as idle */
  460.     hp->tstate = RRTS;
  461.     hp->tx_state = drtx_rrts;
  462. #ifdef DRSIDEBUG
  463.     tputs("drtx_defer - wake posted for drtx_rrts\n");
  464. #endif
  465.     write_scc(base, R9, 0);        /* Interrupts off */
  466.     write_scc(base,R5,RTS|Tx8|DTR);    /* Turn tx on */
  467.     dr_wake(hp, TX, tx_fsm, 10);
  468. }
  469.  
  470. /* drtx_rrts
  471.  * Transmit RRTS state processor
  472.  */
  473. static void
  474. drtx_rrts(struct drchan *hp)
  475. {
  476.     int16 base = hp->base;
  477.  
  478.     write_scc(base, R9, 0);    /* Interrupts off */
  479.     write_scc(base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);    /* Tx now on */
  480.     hp->tstate = TFIRST;
  481.     hp->tx_state = drtx_tfirst;
  482. #ifdef DRSIDEBUG
  483.     tputs("8530 Int status %x\n", read_scc(base+CHANA,R3));
  484.     tputs("drtx_rrts - Wake posted for TXDELAY\n");
  485. #endif
  486.     dr_wake(hp, TX, tx_fsm, hp->txdelay);
  487. }
  488.  
  489. /* drtx_tfirst
  490.  * Transmit TFIRST state processor
  491.  */
  492. static void
  493. drtx_tfirst(struct drchan *hp)
  494. {
  495.     int16 base = hp->base;
  496.     char c;
  497.  
  498.     /* Copy data to a local buffer to save on mbuf overheads
  499.      * during transmit interrupt time.
  500.      */
  501.     hp->drtx_cnt = len_p(hp->sndbuf);
  502.     hp->drtx_tcp = hp->drtx_buffer;
  503.  
  504.     pullup(&hp->sndbuf, hp->drtx_tcp, hp->drtx_cnt);
  505.  
  506.     /* Transmit the first character in the buffer */
  507.     c = *hp->drtx_tcp++;
  508.     hp->drtx_cnt--;
  509.  
  510.     write_scc(base, R0, RES_Tx_CRC);    /* Reset CRC */
  511.     write_scc(base, R0, RES_EOM_L);        /* Reset underrun latch */
  512.     outportb(base+DATA, c);            /* Output first character */
  513.     write_scc(base, R15, TxUIE);        /* Allow underrun ints only */
  514.     write_scc(base, R1, TxINT_ENAB|EXT_INT_ENAB); /* Tx/Ext status ints on */
  515.     write_scc(base, R9, MIE|NV);        /* master enable */
  516.     hp->tstate = ACTIVE;
  517.     hp->tx_state = drtx_active;
  518. }
  519.  
  520. /* drtx_active
  521.  * Transmit ACTIVE state processor
  522.  */
  523. static void
  524. drtx_active(struct drchan *hp)
  525. {
  526.     if(hp->drtx_cnt-- > 0){
  527.         /* Send next character */
  528.         outportb(hp->base+DATA, *hp->drtx_tcp++);
  529.     } else {
  530.         /* No more to send - wait for underrun to hit */
  531.         hp->tstate = UNDERRUN;
  532.         hp->tx_state = drtx_flagout;
  533.         free_p(hp->sndbuf);
  534.         write_scc(hp->base, R0, RES_EOM_L);  /* Send CRC on underrun */
  535.         write_scc(hp->base, R0, RES_Tx_P);   /* Reset Tx Int pending */
  536.     }
  537. }
  538.  
  539. /* drtx_flagout
  540.  * Transmit FLAGOUT state processor
  541.  */
  542. static void
  543. drtx_flagout(struct drchan *hp)
  544. {
  545.     /* Arrive here after CRC sent and Tx interrupt fires.
  546.      * Post a wake for ENDDELAY
  547.      */
  548.  
  549.     hp->tstate = UNDERRUN;
  550.     hp->tx_state = drtx_downtx;
  551.     write_scc(hp->base, R9, 0);
  552.     write_scc(hp->base, R0,  RES_Tx_P);
  553.     dr_wake(hp, TX, tx_fsm, hp->enddelay);
  554. }
  555.  
  556. /* drtx_downtx
  557.  * Transmit DOWNTX state processor
  558.  */
  559. static void
  560. drtx_downtx(struct drchan *hp)
  561. {
  562.     int base = hp->base;
  563.  
  564.     /* See if theres anything left to send - if there is,  send it ! */
  565.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  566.         /* Nothing left to send - return to receive */
  567.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  568.         write_scc(base, R0, ERR_RES);   /* Reset error bits */
  569.         hp->tstate = IDLE;
  570.         hp->tx_state = drtx_idle;
  571.         hp->rstate = ENABLE;
  572.         hp->rx_state = drrx_enable;
  573.         drrx_enable(hp);
  574.     } else
  575.         drtx_tfirst(hp);
  576.  
  577. }
  578.  
  579. /* Write CTC register */
  580. static void
  581. write_ctc(unsigned port,unsigned reg,unsigned val)
  582. {
  583.     int16 base = port;
  584.  
  585.     DISABLE();
  586.     /* Select register */
  587.     outportb(base+Z8536_MASTER,reg);
  588.     outportb(base+Z8536_MASTER,val);
  589.     RESTORE();
  590. }
  591.  
  592. /* Read CTC register */
  593. static char
  594. read_ctc(unsigned port,unsigned reg)
  595. {
  596.     char c;
  597.     int16 i, base = port;
  598.  
  599.     DISABLE();
  600.     /* Select register */
  601.     outportb(base+Z8536_MASTER,(reg & 0xFF));
  602.  
  603.     /* Delay for a short time to allow 8536 to settle */
  604.     for(i = 0; i < 100; i++) ;
  605.  
  606.     c = inportb(base+Z8536_MASTER);
  607.     RESTORE();
  608.  
  609.     return(c & 0xFF);
  610. }
  611.  
  612. /* Initialize dr controller parameters */
  613. static int
  614. drchanparam(struct drchan *hp)
  615. {
  616.     int16 tc;
  617.     long br;
  618.  
  619.     /* Initialize 8530 channel for SDLC operation */
  620.     int16 base = hp->base;
  621.  
  622.     DISABLE();
  623.     switch(base & 2){
  624.     case 2:
  625.         write_scc(base,R9,CHRA);    /* Reset channel A */
  626.         break;
  627.     case 0:
  628.         write_scc(base,R9,CHRB);    /* Reset channel B */
  629.         break;
  630.     }
  631.     /* Deselect all Rx and Tx interrupts */
  632.     write_scc(base,R1,0);
  633.  
  634.     /* Turn off external interrupts (like CTS/CD) */
  635.     write_scc(base,R15,0);
  636.  
  637.     /* X1 clock, SDLC mode */
  638.     write_scc(base,R4,SDLC|X1CLK);     /* SDLC mode and X1 clock */
  639.  
  640.     /* Now some misc Tx/Rx parameters */
  641.     /* CRC PRESET 1, NRZI Mode */
  642.     write_scc(base,R10,CRCPS|NRZI);
  643.  
  644.     /* Set up BRG and DPLL multiplexers */
  645.     /* Tx Clk from RTxC. Rcv Clk from DPLL, TRxC pin outputs BRG */
  646.     write_scc(base,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
  647.  
  648.     /* Null out SDLC start address */
  649.     write_scc(base,R6,0);
  650.  
  651.     /* SDLC flag */
  652.     write_scc(base,R7,FLAG);
  653.  
  654.     /* Set up the Transmitter but don't enable it */
  655.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  656.     write_scc(base,R5,Tx8|DTR);
  657.  
  658.     /* Receiver - initial setup only - more later */
  659.     write_scc(base,R3,Rx8);         /* 8 bits/char */
  660.  
  661.     /* Setting up BRG now - turn it off first */
  662.     write_scc(base,R14,BRSRC);     /* BRG off, but keep Pclk source */
  663.  
  664.     /* set the 32x time constant for the BRG */
  665.  
  666.     br = hp->speed;            /* get desired speed */
  667.     tc = ((XTAL/32)/br)-2;        /* calc 32X BRG divisor */
  668.  
  669.     write_scc(base,R12,tc&0xFF);      /* lower byte */
  670.     write_scc(base,R13,(tc>>8)&0xFF); /* upper bite */
  671.  
  672.     /* Time to set up clock control register for RECEIVE mode
  673.      * DRSI has xtal osc going to pclk at 4.9152 Mhz
  674.      * The BRG is sourced from that, and set to 32x clock
  675.      * The DPLL is sourced from the BRG.  BRG is fed to the TRxC pin
  676.      * Transmit clock is provided by the BRG externally divided by
  677.      * 32 in the CTC counter 1 and 2.
  678.      * Receive clock is from the DPLL
  679.      */
  680.  
  681.     /* Following subroutine sets up and ENABLES the receiver */
  682.     drrx_enable(hp);
  683.  
  684.     /* DPLL from BRG, BRG source is PCLK */
  685.     write_scc(hp->base,R14,BRSRC|SSBR);
  686.     /* SEARCH mode, keep BRG source */
  687.     write_scc(hp->base,R14,BRSRC|SEARCH);
  688.     /* Enable the BRG */
  689.     write_scc(hp->base,R14,BRSRC|BRENABL);
  690.  
  691.     /* enable the receive interrupts */
  692.  
  693.     write_scc(hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  694.     write_scc(hp->base,R15,BRKIE);    /* ABORT int */
  695.     write_scc(hp->base,R9,MIE|NV);    /* master enable */
  696.  
  697.  
  698.     /* Now, turn on the receiver and hunt for a flag */
  699.     write_scc(hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  700.  
  701.     RESTORE();
  702.     return 0;
  703. }
  704.  
  705. /*
  706.  * Initialize the CTC (8536)
  707.  * Only the counter/timers are used - the IO ports are un-comitted.
  708.  * Channels 1 and 2 are linked to provide a /32 counter to convert
  709.  * the SIO BRG to a real clock for Transmit clocking.
  710.  * CTC 3 is left free running on a 10 mS period.  It is always polled
  711.  * and therefore all interrupts from the chip are disabled.
  712.  *
  713.  * Updated 02/16/89 by N6TTO
  714.  * Changed to support the use of the second channel on the 8530.
  715.  * Added so that the driver works on the DRSI type 2 PC Adaptor
  716.  * which has 2 1200 bps modems.
  717.  *
  718.  */
  719. static void
  720. drinitctc(unsigned port)
  721. {
  722.     long i;
  723.  
  724.     /* Initialize 8536 CTC */
  725.  
  726.     /* Initialize 8536 */
  727.     /* Start by forcing chip into known state */
  728.     read_ctc(port, Z8536_MICR);
  729.  
  730.     write_ctc(port, Z8536_MICR, 0x01);    /* Reset the CTC */
  731.     for(i = 0; i < 1000L; i++) ;        /* Loop to delay */
  732.  
  733.     write_ctc(port, Z8536_MICR, 0x00);    /* Clear reset and start init seq. */
  734.  
  735.     /* Wait for chip to come ready */
  736.     while((read_ctc(port, Z8536_MICR)) != 0x02)    ;
  737.  
  738.     write_ctc(port, Z8536_MICR, 0xa6);    /* MIE|NV|CT_VIS|RJA */
  739.     write_ctc(port, Z8536_MCCR, 0xf4);    /* PBE|CT1E|CT2E|CT3E|PAE */
  740.  
  741.     write_ctc(port, Z8536_CTMS1, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  742.     write_ctc(port, Z8536_CTMS2, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  743.     write_ctc(port, Z8536_CTMS3, 0x80);    /* Continuous,Pulse output */
  744.     write_ctc(port, Z8536_CT1MSB, 0x00);    /* Load time constant CTC #1 */
  745.     write_ctc(port, Z8536_CT1LSB, 0x10);
  746.     write_ctc(port, Z8536_CT2MSB, 0x00);    /* Load time constant CTC #2 */
  747.     write_ctc(port, Z8536_CT2LSB, 0x10);
  748.     write_ctc(port, Z8536_CT3MSB, 0x60);    /* Load time constant CTC #3 */
  749.     write_ctc(port, Z8536_CT3LSB, 0x00);
  750.  
  751.     write_ctc(port, Z8536_IVR, 0x06);
  752.  
  753.     /* Set port direction bits in port A and B
  754.      * Data is input on bits d1 and d5, output on d0 and d4.
  755.      * The direction is set by 1 for input and 0 for output
  756.      */
  757.     write_ctc(port, Z8536_PDCA, 0x22);
  758.     write_ctc(port, Z8536_PDCB, 0x22);
  759.  
  760.     write_ctc(port, Z8536_CSR1, Z_GCB|Z_TCB);  /* Start CTC #1 running */
  761.     write_ctc(port, Z8536_CSR2, Z_GCB|Z_TCB);  /* Start CTC #2 running */
  762.     write_ctc(port, Z8536_CSR3, Z_IE|Z_GCB|Z_TCB); /* Start CTC #3 running */
  763. }
  764.  
  765. /* Attach a DRSI interface to the system
  766.  * argv[0]: hardware type, must be "drsi"
  767.  * argv[1]: I/O address, e.g., "0x300"
  768.  * argv[2]: vector, e.g., "2"
  769.  * argv[3]: mode, must be:
  770.  *        "ax25" (AX.25 UI frame format)
  771.  * argv[4]: iface label, e.g., "dr0"
  772.  * argv[5]: receiver packet buffer size in bytes
  773.  * argv[6]: maximum transmission unit, bytes
  774.  * argv[7]: iface speed for channel A
  775.  * argv[8]: iface speed for channel B (defaults to same as A if absent)
  776.  *  notused:
  777.  * argv[9]: First IP address, optional (defaults to Ip_addr)
  778.  * argv[10]: Second IP address, optional (defaults to Ip_addr)
  779.  */
  780. int
  781. dr_attach(int argc,char **argv,void *p)
  782. {
  783.     struct iface *if_pca, *if_pcb;
  784.     struct drchan *hp;
  785.     int dev;
  786.  
  787.     /* Quick check to make sure args are good and mycall is set */
  788.     if(*Mycall == '\0'){
  789.         tputs(Nomycall);
  790.         return -1;
  791.     }
  792.     if(strcmp(argv[3],"ax25") != 0){
  793.         tputs("Mode must be ax25\n");
  794.         return -1;
  795.     }
  796.     if(if_lookup(argv[4]) != NULLIF) {
  797.         tprintf(Ifexist,argv[4]);
  798.         return -1;
  799.     }
  800.     /* Note: More than one card can be supported if you give up a COM:
  801.      * port, thus freeing up an IRQ line and port address
  802.      */
  803.     if(Drnbr >= DRMAX){
  804.         tprintf("Max %d DRSI controllers\n",DRMAX);
  805.         return -1;
  806.     }
  807.     dev = Drnbr++;
  808.  
  809.     /* Initialize hardware-level control structure */
  810.     Drsi[dev].addr = htoi(argv[1]);
  811.     Drsi[dev].vec = htoi(argv[2]);
  812.  
  813.     /* Save original interrupt vector */
  814.     Drsi[dev].oldvec = getirq(Drsi[dev].vec);
  815.  
  816.     /* Set new interrupt vector */
  817.     if(setirq(Drsi[dev].vec,Drhandle[dev]) == -1){
  818.         tprintf("IRQ %u out of range\n",Drsi[dev].vec);
  819.         Drnbr--;
  820.     }
  821.     /* Initialize the CTC */
  822.     drinitctc(Drsi[dev].addr);
  823.  
  824.     /* Create iface structures and fill in details */
  825.     if_pca = mxallocw(sizeof(struct iface));
  826.     if_pcb = mxallocw(sizeof(struct iface));
  827.  
  828.     if_pca->addr = Ip_addr;
  829.     if_pcb->addr = Ip_addr;
  830.  
  831.     /* Append "a" and "b" to iface name */
  832.     if_pca->name = strxdup(argv[4]);
  833.     if_name(if_pca,"a");
  834.     if_pcb->name = strxdup(argv[4]);
  835.     if_name(if_pcb,"b");
  836.  
  837.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  838.     if_pcb->type = if_pca->type = CL_AX25;
  839.     if_pcb->ioctl = if_pca->ioctl = dr_ctl;
  840.     if_pca->dev = 2*dev;            /* dr0a */
  841.     if_pcb->dev = 2*dev + 1;        /* dr0b */
  842.     if_pcb->stop = if_pca->stop = dr_stop;
  843.     if_pcb->raw = if_pca->raw = dr_raw;
  844.  
  845.     if_pca->hwaddr = strxdup(Mycall);
  846.     setencap(if_pca,"AX25");
  847.     if_pcb->hwaddr = strxdup(Mycall);
  848.     setencap(if_pcb,"AX25");
  849.  
  850.     /* Link em in to the iface chain */
  851.     if_pca->next = if_pcb;
  852.     if_pcb->next = Ifaces;
  853.     Ifaces = if_pca;
  854.     if_pca->niface = Niface++;
  855.     if_pcb->niface = Niface++;
  856.     init_maxheard(if_pca);
  857.     init_maxheard(if_pcb);
  858.     init_flags(if_pca);
  859.     init_flags(if_pcb);
  860.  
  861.     /* set params in drchan table for CHANNEL B */
  862.     hp = &Drchan[2*dev+1];                /* dr1 is offset 1 */
  863.     hp->iface = if_pcb;
  864.     hp->stata = Drsi[dev].addr + CHANA + CTL;    /* permanent status */
  865.     hp->statb = Drsi[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  866.     if(argc > 8){
  867.         /* Separate speed for channel B */
  868.         hp->speed = (int16)atol(argv[8]);
  869.     } else {
  870.         /* Set speed to same as for channel A */
  871.         hp->speed = (int16)atol(argv[7]);
  872.     }
  873.     hp->base = Drsi[dev].addr + CHANB;
  874.     hp->bufsiz = atoi(argv[5]);
  875.     hp->drtx_buffer = mxallocw(if_pcb->mtu + 100);
  876.     hp->tstate = IDLE;
  877.     hp->tx_state = drtx_idle;
  878.     hp->w[RX].wcall = NULL;
  879.     hp->w[RX].wakecnt = 0;
  880.     hp->w[TX].wcall = NULL;
  881.     hp->w[TX].wakecnt = 0;
  882.     /* default KISS Params */
  883.     hp->txdelay = 25;            /* 250 Ms */
  884.     hp->persist = 64;            /* 25% persistence */
  885.     hp->slotime = 10;            /* 100 Ms */
  886.     hp->squeldelay = 20;        /* 200 Ms */
  887.     hp->enddelay = 10;            /* 100 Ms */
  888.  
  889.     write_scc(hp->stata,R9,FHWRES);        /* Hardware reset */
  890.  
  891.     /* Disable interrupts with Master interrupt ctrl reg */
  892.     write_scc(hp->stata,R9,0);
  893.  
  894.     drchanparam(hp);
  895.  
  896.     /* Initialize buffer pointers */
  897.     hp->rcvbuf = NULLBUF;
  898.     hp->rcvbuf->cnt = 0;
  899.     hp->sndq = NULLBUF;
  900.  
  901.     /* set params in drchan table for CHANNEL A */
  902.     hp = &Drchan[2*dev];            /* dr0a is offset 0 */
  903.     hp->iface = if_pca;
  904.     hp->speed = (int16)atol(argv[7]);
  905.     hp->base = Drsi[dev].addr + CHANA;
  906.     hp->bufsiz = atoi(argv[5]);
  907.     hp->drtx_buffer = mxallocw(if_pca->mtu + 100);
  908.     hp->tstate = IDLE;
  909.     hp->tx_state = drtx_idle;
  910.     hp->w[RX].wcall = NULL;
  911.     hp->w[RX].wakecnt = 0;
  912.     hp->w[TX].wcall = NULL;
  913.     hp->w[TX].wakecnt = 0;
  914.     /* default KISS Params */
  915.     hp->txdelay = 30;            /* 300 Ms */
  916.     hp->persist = 64;            /* 25% persistence */
  917.     hp->slotime = 10;            /* 100 Ms */
  918.     hp->squeldelay = 20;        /* 200 Ms */
  919.     hp->enddelay = 10;            /* 100 Ms */
  920.  
  921.     drchanparam(hp);
  922.  
  923.     /* Initialize buffer pointers */
  924.     hp->rcvbuf = NULLBUF;
  925.     hp->rcvbuf->cnt = 0;
  926.     hp->sndq = NULLBUF;
  927.  
  928.     write_scc(hp->base,R9,MIE|NV);        /* master interrupt enable */
  929.  
  930.     /* Enable interrupt in 8259 interrupt controller */
  931.     maskon(Drsi[dev].vec);
  932.  
  933.     return 0;
  934. }
  935.  
  936. /* Shut down iface */
  937. static int
  938. dr_stop(struct iface *iface,int tmp)
  939. {
  940.     int16 dev = iface->dev;
  941.  
  942.     if(dev & 1)
  943.         return 0;
  944.  
  945.     dev >>= 1;    /* Convert back into DRSI number */
  946.  
  947.     /* Set 8259 interrupt mask (turn off interrupts) */
  948.     maskoff(Drsi[dev].vec);
  949.  
  950.     /* Restore original interrupt vector */
  951.     setirq(Drsi[dev].vec, Drsi[dev].oldvec);
  952.     Drnbr--;
  953.  
  954.     /* Force hardware reset */
  955.     write_scc(Drsi[dev].addr + CHANA + CTL,R9,FHWRES);
  956.     /* Reset the CTC */
  957.     (void) read_ctc(Drsi[dev].addr, Z8536_MICR);
  958.     write_ctc(Drsi[dev].addr, Z8536_MICR, 0x01);
  959.     return 0;
  960. }
  961.  
  962. /* Send raw packet on DRSI card */
  963. static int
  964. dr_raw(struct iface *iface,struct mbuf *bp)
  965. {
  966.     char kickflag;
  967.     struct drchan *hp = &Drchan[iface->dev];
  968.  
  969.     DISABLE();
  970.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  971.     kickflag = (hp->sndq == NULL) & (hp->sndbuf == NULLBUF);
  972.     /* clever! flag=1 if something in queue */
  973.     enqueue(&hp->sndq,bp);
  974.  
  975.     if(kickflag)            /* simulate interrupt to xmit */
  976.         tx_fsm(hp);            /* process interrupt */
  977.  
  978.     RESTORE();
  979.     return 0;
  980. }
  981.  
  982. /* display DRSI Channel stats */
  983. int
  984. dodrstat(int argc,char **argv,void *p)
  985. {
  986.     int i, j;
  987.  
  988.     tputs("DRSI Board Statistics - N6TTO 112790.0\n");
  989.  
  990.     for(i = 0; i < DRMAX; i++) {
  991.         for(j = 0; j < 2; j++) {
  992.             struct drchan *hp = &Drchan[j + i];
  993.  
  994.             tprintf("Channel %s\nRxints  %8ld  Txints  %8ld  Exints  %8ld\n",
  995.                 hp->iface->name, hp->rxints, hp->txints, hp->exints);
  996.             tprintf("Enqued  %8ld  Crcerr  %8ld  Aborts  %8ld\n",
  997.                 hp->enqueued, hp->crcerr, hp->aborts);
  998.             tprintf("RFrames %8ld  Rxovers %8ld  TooBig  %8ld\n",
  999.                 hp->rxframes, hp->rovers, hp->toobig);
  1000.             tprintf("Txdefer %8ld  Txppers %8ld  Nomem   %8ld\n",
  1001.                 hp->txdefers, hp->txppersist, hp->nomem);
  1002.             tprintf("TxState %8d  RxState %8d\n\n",
  1003.                 hp->tstate,hp->rstate);
  1004.         }
  1005.     }
  1006.     return 0;
  1007. }
  1008.  
  1009. /* Subroutine to set kiss params in channel tables */
  1010. static int32
  1011. dr_ctl(struct iface *iface,int cmd,int set,int32 val)
  1012. {
  1013.     struct drchan *hp = &Drchan[iface->dev];
  1014.  
  1015.     switch(cmd){
  1016.     case PARAM_TXDELAY:
  1017.         if(set)
  1018.             hp->txdelay = (int)val;
  1019.         return hp->txdelay;
  1020.     case PARAM_PERSIST:
  1021.         if(set)
  1022.             hp->persist = (int)val;
  1023.         return hp->persist;
  1024.     case PARAM_SLOTTIME:
  1025.         if(set)
  1026.             hp->slotime = (int)val;
  1027.         return hp->slotime;
  1028.     case PARAM_TXTAIL:
  1029.         if(set)
  1030.             hp->squeldelay = (int)val;
  1031.         return hp->squeldelay;
  1032.     case PARAM_ENDDELAY:
  1033.         if(set)
  1034.             hp->enddelay = (int)val;
  1035.         return hp->enddelay;
  1036.     case PARAM_SPEED:
  1037.         return hp->speed;
  1038.     }
  1039.     return -1;
  1040. }
  1041.  
  1042. #endif /* DRSI */
  1043.